package com.sian.anyun.web.services;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;

import org.atmosphere.cpr.AtmosphereResource;
import org.atmosphere.cpr.BroadcasterCache;
import org.atmosphere.cpr.BroadcasterFactory;
import org.atmosphere.cpr.Broadcaster;
import org.codehaus.jackson.map.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.sian.anyun.web.model.BroadcastMessage;

@Service
public class BroadcasterService {
	public final static String SYSTEM_BROADCAST_ID = "/root";
	private static final Logger logger = LoggerFactory.getLogger(BroadcasterService.class);
	
	@Autowired
	PresentService presentService;
	
	private long sinceId = 0;
	Map<String, Broadcaster> broadcasters = new HashMap<String, Broadcaster>();
	
	public BroadcasterService() 
	{
		final ObjectMapper mapper = new ObjectMapper();
		Broadcaster broadcaster = BroadcasterFactory.getDefault().get(SYSTEM_BROADCAST_ID);
		broadcaster.scheduleFixedBroadcast(new Callable<String>() {
			// @Override
			public String call() throws Exception {
				List<BroadcastMessage> broadcastMessages = new ArrayList<BroadcastMessage>();
				for (int i = 0; i < 3; i++) {
					broadcastMessages.add(
							new BroadcastMessage(sinceId++, 
									new Date(),
									"Message #" + sinceId,
									"SYSTEM_BROADCAST", null));
				}

				return mapper.writeValueAsString(broadcastMessages);
			}

		}, 10, TimeUnit.SECONDS);
		
		broadcasters.put(SYSTEM_BROADCAST_ID, broadcaster);
	}
	
	private String parserName(String name)
	{
		if(null == name)
			return "";
		else
		{
			name = name.trim();
			while(name.startsWith("/"))
			{
				name = name.substring(1);
			}
		}

		if(0 == name.length())
			return "";
		else
			return "/" + name;
	}
	
	public void createBroadcaster(String name)
	{		
		if(broadcasters.containsKey(SYSTEM_BROADCAST_ID + parserName(name)))
		{
			logger.error("Broadcaster " + name + " is existing");
			throw new RuntimeException("Broadcaster " + name + " is existing");
		}

		Broadcaster broadcaster = BroadcasterFactory.getDefault().lookup(name);
		broadcasters.put(name, broadcaster);
	}
	
	public void removeBroadcaster(String name)
	{
		Broadcaster broadcaster = broadcasters.get(SYSTEM_BROADCAST_ID + parserName(name));
		if(null != broadcaster)
		{
			broadcasters.remove(name);
			broadcaster.destroy();
		}
	}

	public void setBroadcasters(List<String> names)
	{
		for(String name:names)
		{
			createBroadcaster(name);
		}
	}

	public void subscribeToBroadcaster(String name, AtmosphereResource resource)
	{
		Broadcaster bc = broadcasters.get(SYSTEM_BROADCAST_ID + parserName(name));
		if(null != bc)
		{
			bc.addAtmosphereResource(resource);
		}
		else
		{
			logger.error("No broadcaster " + name + " was found");
			throw new RuntimeException("No broadcaster " + name + " was found");
		}
	}

	public void subscribeToSystemBroadcaster(AtmosphereResource resource)
	{
		subscribeToBroadcaster("", resource);
	}
	
	public void unsubscribeFromBroadcaster(String name, AtmosphereResource resource)
	{
		Broadcaster bc = broadcasters.get(SYSTEM_BROADCAST_ID + parserName(name));
		bc.removeAtmosphereResource(resource);
	}
	
	public void unsubscribeFromSystemBroadcaster(AtmosphereResource resource)
	{
		unsubscribeFromBroadcaster("", resource);
	}

	public void broadcast(String name, Object message)
	{
		Broadcaster bc = broadcasters.get(SYSTEM_BROADCAST_ID + parserName(name));
		if(null != bc)
		{
			bc.broadcast(message);
		}
		else
		{
			logger.error("No broadcaster " + name + " was found");
			throw new RuntimeException("No broadcaster " + name + " was found");
		}
	}

	public void systemBroadcast(Object message)
	{
		broadcast("", message);
	}

	public BroadcasterCache getBroadcastCatch(String name)
	{
		Broadcaster bc =  broadcasters.get(SYSTEM_BROADCAST_ID + parserName(name));
		return bc.getBroadcasterConfig().getBroadcasterCache();
	}
	
	public BroadcasterCache getSystemBroadcastCatch()
	{
		return getBroadcastCatch("");
	}

	public void sendMessageToPeer(String from, String to, Object message)
	{
		AtmosphereResource resource = presentService.getAtmosphereResource(to);
		resource.getBroadcaster().broadcast(message);
		//resource.suspend();
	}
}
